import re
import sys
from transport import BaseTransport, SSHTransport, TelnetTransport

class DeviceError(Exception):
    def __init__(self,value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class NotSupportedByDeviceError(DeviceError): pass

class BaseDevice(object):
    """
     Base class for defining a device
    """
     PROMPT = "[\$%#>]"
     PAGER_PROMPT = "--[Mm]ore--"

     def __init__(self, transport = SSHTransport,
                  prompt='',
                  pager_prompt='',
                  auth_failures='',
                  error_fmt=''):

        if not issubclass(transport, BaseTransport):
            raise TypeError

        self.transport = transport(prompt = self.PROMPT,
                                   pager_prompt = self.PAGER_PROMPT)

    def connect(self, host, username, password):
        self.transport.open(host, username, password)

    def disconnect(self):
        self.transport.close()

    def cmd(self, cmd):
        return self.transport.cmd(cmd)

    def get_current_config(self):
        raise NotSupportedByDeviceError
 
    def get_startup_config(self):
        raise NotSupportedByDeviceError

    def get_version(self):
        raise NotSupportedByDeviceError

    def get_tech_support(self):
        raise NotSupportedByDeviceError

    def interact(self):
        sys.stdout.write(self.transport.last_prompt)
        try:
            self.transport.child.interact()
        except OSError:
            self.transport.close()


class EnableDevice(BaseDevice):
    def __init__(self, autoenable=True, 
                       enablepass="", 
                       *args, **kwargs):
        super(EnableDevice, self).__init__(*args, **kwargs)
        self.autoenable = autoenable
        self.enablepass = enablepass

    def connect(self, *args, **kwargs):
        super(EnableDevice, self).connect(*args, **kwargs)
        if (self.autoenable):
            self.enable()

    def enable(self):
        if (re.search('[\w().-]+\s?>\s*', self.transport.last_prompt)):
            self.transport.child.sendline('enable')
            self.transport.child.expect('(Enter)?\s?[Pp]assword:')
            self.transport.child.sendline(self.enablepass)
            self.transport.child.expect(self.transport.prompt)    
      

class IOSDevice(EnableDevice, BaseDevice):
    """ Cisco systems IOS device """
    PROMPT = re.compile('\r\n[\w().-]+\s?(\(config[^\)]*\))?\s?[\$#>]\s*')
    PAGER_PROMPT = re.compile('\s*--More--')

    def connect(self, *args, **kwargs):
        super(IOSDevice, self).connect(*args, **kwargs)
        self.cmd('terminal length 0')

    def get_current_config(self):
        return self.cmd('show running-config')
 
    def get_startup_config(self):
        return self.cmd('show startup-config')

    def get_version(self):
        return self.cmd('show version')

    def get_tech_support(self):
        return self.cmd('show tech-support')

    def interact(self):
        self.cmd('term no length')
        super(IOSDevice, self).interact()


class CatOSDevice(EnableDevice, BaseDevice):
    PROMPT = re.compile('\r\n[\w().-]+\s?(\(config[^\)]*\))?\s?[\$#>]\s*')
    PAGER_PROMPT = re.compile('\s*--More--')

    def connect(self, *args, **kwargs):
        super(IOSDevice, self).connect(*args, **kwargs)
        self.cmd('set length 0')

    def get_current_config(self):
        return self.cmd('show configuration')
 
    def get_version(self):
        return self.cmd('show version')


class JunOSDevice(BaseDevice):
    PROMPT = re.compile('/w+@/w>')
    PAGER_PROMPT = '--More--'

    def get_current_config(self):
        return self.cmd('show configuration')
 
    def get_version(self):
        return self.cmd('show system version')


class ScreenOSDevice(BaseDevice):
    PROMPT = re.compile('\r\n[\w().-]+\s?->\s*')
    PAGER_PROMPT = '--More--'

    def get_current_config(self):
        return self.cmd('get config')
 
    def get_version(self):
        return self.cmd('get system version')


class EOSDevice(EnableDevice, BaseDevice):
    """ Device class for Arista Networks EOS device"""
    PROMPT = self.transport.prompt = re.compile('[\w().-]+\s?(\(config[^\)]*\))?\s?[\$#>]\s*')
    PAGER_PROMPT = re.compile('\s*--More--')


